package com.kanshu.ksgb.fastread.doudou.common.security;

import android.content.Context;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Base64;

import com.kanshu.ksgb.fastread.doudou.app.Xutils;
import com.kanshu.ksgb.fastread.doudou.common.util.StorageUtils;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES128 加密方式实现加解密接口
 * @author wanchunyang
 */
class MyAES implements ISecurity {

    /**
     * 模式定义
     */
    private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";

    private static final String CHARSET = "utf-8";

    /**
     * 导出密钥字节长度
     */
    static final int PBKDF2_KEY_SIZE = 16 * 8;

    /**
     * 生成的盐值位数
     */
    private static final int PBKDF2_SALT_SIZE = 512;

    /**
     * 迭代次数
     */
    private static final int PBKDF2_HASH_ROUNDS = 10000;

    private static final String PBKDF2_PASSCODE = "wetalk_txt";

    private final SecureRandom mRng = new SecureRandom();

    private static final String SHARED_KEY_SALT = "wt_salt_user_key";

    private static final String SHARED_KEY_RADOM = "wt_secure_radom_key";

    private static final String SHARED_SECURITY_NAME = "wt_secdb_name";

    private byte[] mScretKey;

    private Cipher getCipher(int mode) {
        SecretKeySpec secretKeySpec = new SecretKeySpec(getSecretKey(), "AES");
        IvParameterSpec iv = new IvParameterSpec(getSecretKey());
        Cipher mkC = null;
        try {
            mkC = Cipher.getInstance(TRANSFORMATION);
            mkC.init(mode, secretKeySpec, iv);
        }
        catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
        catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        return mkC;
    }

    private SecretKey buildCharArrayKey(char[] pwArray, byte[] salt, int rounds) {
        try {
            PBEKeySpec spec = new PBEKeySpec(pwArray, salt, PBKDF2_HASH_ROUNDS, PBKDF2_KEY_SIZE);
            SecretKeyFactory kf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            SecretKey cipherKey = kf.generateSecret(spec);
            return cipherKey;
        }
        catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成盐值
     *
     * @param bits 生成多少位的盐值
     * @return byte[]
     */
    private byte[] randomBytes(int bits) {
        byte[] array = new byte[bits / 8];
        mRng.nextBytes(array);
        return array;
    }

    /**
     * 获取盐值
     * 
     * @return byte[]
     */
    private synchronized byte[] getSecretKey() {
        if (mScretKey == null) {
            
            Context context = Xutils.getContext();
            String scretKey = StorageUtils.getPreference(context, SHARED_SECURITY_NAME, SHARED_KEY_SALT, String.class) +
                    StorageUtils.getPreference(context, SHARED_SECURITY_NAME, SHARED_KEY_RADOM, String.class);
            if (TextUtils.isEmpty(scretKey)) {
                SecretKey key = buildCharArrayKey(getKey(), randomBytes(PBKDF2_SALT_SIZE), PBKDF2_HASH_ROUNDS);
                mScretKey = key.getEncoded();
                scretKey = Base64.encodeToString(mScretKey, Base64.DEFAULT);
                String scretKeySub1 = scretKey.substring(0, scretKey.length() / 3);
                String scretKeySub2 = scretKey.substring(scretKey.length() / 3);
                StorageUtils.setPreference(context, SHARED_SECURITY_NAME, SHARED_KEY_SALT, scretKeySub1);
                StorageUtils.setPreference(context, SHARED_SECURITY_NAME, SHARED_KEY_RADOM, scretKeySub2);
            }
            else {
                mScretKey = Base64.decode(scretKey, Base64.DEFAULT);
            }
        }
        return mScretKey;
    }

    public char[] getKey() {
        Context context = Xutils.getContext();
        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        String device = tm.getDeviceId();
        if (TextUtils.isEmpty(device)) {
            device = "kanshu";
        }
        return (PBKDF2_PASSCODE + System.currentTimeMillis() + device).toCharArray();
    }

    @Override
    public void clear() {
        mScretKey = null;
        Context context = Xutils.getContext();
        StorageUtils.setPreference(context, SHARED_SECURITY_NAME, SHARED_KEY_SALT, "");
        StorageUtils.setPreference(context, SHARED_SECURITY_NAME, SHARED_KEY_RADOM, "");
    }

    @Override
    public String encrypt(String src) throws Exception {
        Cipher cipher = getCipher(Cipher.ENCRYPT_MODE);
        byte[] encrypted = cipher.doFinal(src.getBytes(CHARSET));
        return Base64.encodeToString(encrypted, Base64.DEFAULT);

    }

    @Override
    public String decrypt(String src) throws Exception {
        byte[] encrypted = Base64.decode(src, Base64.DEFAULT);
        Cipher cipher = getCipher(Cipher.DECRYPT_MODE);
        byte[] decrypted = cipher.doFinal(encrypted);
        return new String(decrypted, CHARSET);
    }
}